package com.heima.app.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.heima.app.gateway.config.AuthProperties;
import com.heima.app.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.servlet.AntPathRequestMatcherProvider;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Consumer;

@Component
@Slf4j
public class AppLoginFilter implements GlobalFilter {
    @Autowired
    private AuthProperties authProperties;
    @Autowired

    private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher();
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //注意游客身份
        //1. 获取请求路径
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().toString();
        //2. 判断请求路径是否需要放行,需要放行直接放行
        boolean result = chick(path);
        if (result){
            return chain.filter(exchange);
        }
        //3. 不需要放行就检查是否携带Token, 没有携带返回401
        List<String> tokens = request.getHeaders().get("Token");
        if (tokens.isEmpty()){
            log.info("请求头中没有携带Token");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        //4. 检验Token,验证Token是否为空,为空返回401
        String token = tokens.get(0);
        if (StrUtil.isBlank(token)){
            log.info("请求头中Token为空");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        //5. 提取Token中的载荷,载荷为空直接返回401
        Jws<Claims> claims = AppJwtUtil.getJws(token);
        Claims body = claims.getBody();
        // 验证Token是否过期
        if (AppJwtUtil.verifyToken(body)==1 || AppJwtUtil.verifyToken(body)==2){
            log.info("Token过期");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        String id = body.getId();
        if (StrUtil.isBlank(id)){
            log.info("Token中没有载荷");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        //6. 把载荷提取出来重新装到请求头中,转发给下游服务
        try {
            exchange.mutate().request(new Consumer<ServerHttpRequest.Builder>() {
                @Override
                public void accept(ServerHttpRequest.Builder builder) {
                    builder.header("user_info",id);
                }
            });
            return chain.filter(exchange);
        } catch (Exception e) {
            e.printStackTrace();
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
    }

    private boolean chick(String path) {
        List<String> excludePaths = authProperties.getExcludePaths();
        // 循环匹配
        for (String excludePath : excludePaths) {
            if (ANT_PATH_MATCHER.match(excludePath,path)){
                return true;
            }
        }
        return false;
    }
}
